home *** CD-ROM | disk | FTP | other *** search
/ Sun Solutions 1997 April to September / Sun Solutions CD - APR '97 - SEP '97 (704-3778-12 Rev. H)(Sun Microsystems, Inc.)(1997).iso / products / Hyperion / src / plat_ultrix.c < prev    next >
C/C++ Source or Header  |  1997-02-26  |  13KB  |  591 lines

  1. /*
  2.  * @(#)plat_ultrix.c    1.6    12/26/93
  3.  *
  4.  * ULTRIX 4.2 drive control routines.
  5.  */
  6. static char *ident = "@(#)plat_ultrix.c    1.6 12/26/93";
  7.  
  8. #ifdef ultrix
  9.  
  10. #include <errno.h>
  11. #include <stdio.h>
  12. #include <sys/types.h>
  13. #include <fcntl.h>
  14. #include <sys/param.h>
  15. #include <sys/stat.h>
  16. #include <sys/time.h>
  17. #include <ustat.h>
  18. #include <string.h>
  19. #include <sys/rzdisk.h>
  20. #include <sys/cdrom.h>
  21.  
  22. #include "struct.h"
  23.  
  24. /*
  25.  *   This structure will be filled with the TOC header and all entries.
  26.  * Ultrix doesn't seem to allow getting single TOC entries.
  27.  *                              - Chris Ross (cross@eng.umd.edu)
  28.  */
  29. struct cd_toc_header_and_entries {
  30.     struct cd_toc_header    cdth;
  31.     struct cd_toc_entry        cdte[CDROM_MAX_TRACK+1];
  32. };
  33.  
  34. void *malloc();
  35. char *strchr();
  36.  
  37. int    min_volume = 128;
  38. int    max_volume = 255;
  39.  
  40. extern char    *cd_device;
  41.  
  42. /*
  43.  * find_cdrom
  44.  *
  45.  * Determine the name of the CD-ROM device.
  46.  *
  47.  * Read through the boot records (via a call to uerf) and find the SCSI
  48.  * address of the CD-ROM.
  49.  */
  50. void
  51. find_cdrom()
  52. {
  53.     char    *data, *fgetline();
  54.     FILE    *uerf;
  55.     int    fds[2];
  56.     int    pid;
  57.  
  58.     pipe(fds);
  59.  
  60.     if ((pid = fork()) == 0) {
  61.         close(fds[0]);
  62.         dup2(fds[1], 1);
  63.         execl("/etc/uerf", "uerf", "-R", "-r", "300", NULL);
  64.         execl("/usr/sbin/uerf", "uerf", "-R", "-r", "300", NULL);
  65.         _exit(1);
  66.     } else if (pid < 0) {
  67.         perror("fork");
  68.         exit(1);
  69.     }
  70.  
  71.     close(fds[1]);
  72.     uerf = fdopen(fds[0], "r");
  73.  
  74.     while (data = fgetline(uerf))
  75.         if (strstr(data, "RRD42")) {
  76.             char    *device;
  77.  
  78.             cd_device = (char *)malloc(sizeof("/dev/rrz##c"));
  79.             strcpy(cd_device, "/dev/r");
  80.             device = strstr(data, "rz");
  81.             device[(int)(strchr(device, ' ') - device)] = '\0';
  82.             strcat(cd_device, device);
  83.             strcat(cd_device, "c");
  84.             break;
  85.         }
  86.  
  87.     fclose(uerf);
  88.  
  89.     if (cd_device == NULL) {
  90.         fprintf(stderr,
  91.             "No cdrom (RRD42) is installed on this system\n");
  92.         exit(1);
  93.     }
  94.  
  95.     kill(pid, 15);
  96.     (void)wait((int *)NULL);
  97. }
  98.  
  99. /*
  100.  * Initialize the drive.  A no-op for the generic driver.
  101.  */
  102. int
  103. gen_init(d)
  104.     struct wm_drive    *d;
  105. {
  106.     return (0);
  107. }
  108.  
  109. /*
  110.  * Get the number of tracks on the CD.
  111.  */
  112. int
  113. gen_get_trackcount(d, tracks)
  114.     struct wm_drive    *d;
  115.     int        *tracks;
  116. {
  117.     struct cd_toc_header    hdr;
  118.  
  119.     if (ioctl(d->fd, CDROM_TOC_HEADER, &hdr))
  120.         return (-1);
  121.  
  122.     *tracks = hdr.th_ending_track;
  123.  
  124.     return (0);
  125. }
  126.  
  127. /*
  128.  * Get the start time and mode (data or audio) of a track.
  129.  *
  130.  * XXX - this should get cached, but that means keeping track of ejects.
  131.  */
  132. int
  133. gen_get_trackinfo(d, track, data, startframe)
  134.     struct wm_drive    *d;
  135.     int        track, *data, *startframe;
  136. {
  137.     struct cd_toc                toc;
  138.     struct cd_toc_header            hdr;
  139.     struct cd_toc_header_and_entries    toc_buffer;
  140.  
  141.     if (ioctl(d->fd, CDROM_TOC_HEADER, &hdr))
  142.         return (-1);
  143.  
  144.     bzero((char *)&toc_buffer, sizeof(toc_buffer));
  145.     toc.toc_address_format = CDROM_MSF_FORMAT;
  146.     toc.toc_starting_track = 0;
  147.     toc.toc_alloc_length = (u_short)(((hdr.th_data_len1 << 8) +
  148.                     hdr.th_data_len0) & 0xfff) + 2;
  149.     toc.toc_buffer = (caddr_t)&toc_buffer;
  150.  
  151.     if (ioctl(d->fd, CDROM_TOC_ENTRYS, &toc))
  152.         return (-1);
  153.  
  154.     if (track == 0)
  155.         track = hdr.th_ending_track + 1;
  156.  
  157.     *data = (toc_buffer.cdte[track-1].te_control & CDROM_DATA_TRACK) ? 1:0;
  158.     *startframe = toc_buffer.cdte[track - 1].te_absaddr.msf.m_units*60*75 +
  159.         toc_buffer.cdte[track - 1].te_absaddr.msf.s_units * 75 +
  160.         toc_buffer.cdte[track - 1].te_absaddr.msf.f_units;
  161.  
  162.     return (0);
  163. }
  164.  
  165. /*
  166.  * Get the number of frames on the CD.
  167.  */
  168. int
  169. gen_get_cdlen(d, frames)
  170.     struct wm_drive    *d;
  171.     int        *frames;
  172. {
  173.     int        tmp;
  174.  
  175.     return (gen_get_trackinfo(d, 0, &tmp, frames));
  176. }
  177.  
  178. /*
  179.  * Get the current status of the drive: the current play mode, the absolute
  180.  * position from start of disc (in frames), and the current track and index
  181.  * numbers if the CD is playing or paused.
  182.  */
  183. int
  184. gen_get_drive_status(d, oldmode, mode, pos, track, index)
  185.     struct wm_drive    *d;
  186.     enum cd_modes    oldmode, *mode;
  187.     int        *pos, *track, *index;
  188. {
  189.     struct cd_sub_channel        sc;
  190.     struct cd_subc_channel_data    scd;
  191.  
  192.     /* If we can't get status, the CD is ejected, so default to that. */
  193.     *mode = EJECTED;
  194.  
  195.     sc.sch_address_format    = CDROM_MSF_FORMAT;
  196.     sc.sch_data_format    = CDROM_CURRENT_POSITION;
  197.     sc.sch_track_number    = 0;
  198.     sc.sch_alloc_length    = sizeof(scd);
  199.     sc.sch_buffer        = (caddr_t)&scd;
  200.  
  201.     /* Is the device open? */
  202.     if (d->fd < 0)
  203.     {
  204.         switch (wmcd_open(d)) {
  205.         case -1:    /* error */
  206.             return (-1);
  207.  
  208.         case 1:        /* retry */
  209.             return (0);
  210.         }
  211.     }
  212.  
  213.     if (ioctl(d->fd, CDROM_READ_SUBCHANNEL, &sc))
  214.         return (0);    /* ejected */
  215.  
  216.     switch (scd.scd_header.sh_audio_status) {
  217.     case AS_PLAY_IN_PROGRESS:
  218.         *mode = PLAYING;
  219. dopos:
  220.         *pos = scd.scd_position_data.scp_absaddr.msf.m_units * 60 * 75 +
  221.             scd.scd_position_data.scp_absaddr.msf.s_units * 75 +
  222.             scd.scd_position_data.scp_absaddr.msf.f_units;
  223.         *track = scd.scd_position_data.scp_track_number;
  224.         *index = scd.scd_position_data.scp_index_number;
  225.         break;
  226.  
  227.     case AS_PLAY_PAUSED:
  228.         if (oldmode == PLAYING || oldmode == PAUSED)
  229.         {
  230.             *mode = PAUSED;
  231.             goto dopos;
  232.         }
  233.         else
  234.             *mode = STOPPED;
  235.         break;
  236.  
  237.     case AS_PLAY_COMPLETED:
  238.         *mode = TRACK_DONE; /* waiting for next track. */
  239.         break;
  240.  
  241.     case AS_NO_STATUS:
  242.         *mode = STOPPED;
  243.         break;
  244.     }
  245.  
  246.     return (0);
  247. }
  248.  
  249. /*
  250.  * scale_volume(vol, max)
  251.  *
  252.  * Return a volume value suitable for passing to the CD-ROM drive.  "vol"
  253.  * is a volume slider setting; "max" is the slider's maximum value.
  254.  *
  255.  * On Sun and DEC CD-ROM drives, the amount of sound coming out the jack
  256.  * increases much faster toward the top end of the volume scale than it
  257.  * does at the bottom.  To make up for this, we make the volume scale look
  258.  * sort of logarithmic (actually an upside-down inverse square curve) so
  259.  * that the volume value passed to the drive changes less and less as you
  260.  * approach the maximum slider setting.  The actual formula looks like
  261.  *
  262.  *     (max^2 - (max - vol)^2) * (max_volume - min_volume)
  263.  * v = --------------------------------------------------- + min_volume
  264.  *                           max^2
  265.  *
  266.  * If your system's volume settings aren't broken in this way, something
  267.  * like the following should work:
  268.  *
  269.  *    return ((vol * (max_volume - min_volume)) / max + min_volume);
  270.  */
  271. scale_volume(vol, max)
  272.     int    vol, max;
  273. {
  274.     return ((max * max - (max - vol) * (max - vol)) *
  275.         (max_volume - min_volume) / (max * max) + min_volume);
  276. }
  277.  
  278. /*
  279.  * Set the volume level for the left and right channels.  Their values
  280.  * range from 0 to 100.
  281.  */
  282. int
  283. gen_set_volume(d, left, right)
  284.     struct wm_drive    *d;
  285.     int        left, right;
  286. {
  287.     struct cd_playback        pb;
  288.     struct cd_playback_status    ps;
  289.     struct cd_playback_control    pc;
  290.  
  291.     left = scale_volume(left, 100);
  292.     right = scale_volume(right, 100);
  293.  
  294.     bzero((char *)&pb, sizeof(pb));
  295.     bzero((char *)&ps, sizeof(ps));
  296.     bzero((char *)&pc, sizeof(pc));
  297.  
  298.     pb.pb_alloc_length = sizeof(ps);
  299.     pb.pb_buffer = (caddr_t)&ps;
  300.  
  301.     if (ioctl(d->fd, CDROM_PLAYBACK_STATUS, &pb))
  302.         return (-1);
  303.  
  304.     pc.pc_chan0_select = ps.ps_chan0_select;
  305.     pc.pc_chan0_volume = (left < CDROM_MIN_VOLUME) ?
  306.         CDROM_MIN_VOLUME : (left > CDROM_MAX_VOLUME) ?
  307.         CDROM_MAX_VOLUME : left;
  308.     pc.pc_chan1_select = ps.ps_chan1_select;
  309.     pc.pc_chan1_volume = (right < CDROM_MIN_VOLUME) ?
  310.         CDROM_MIN_VOLUME : (right > CDROM_MAX_VOLUME) ?
  311.         CDROM_MAX_VOLUME : right;
  312.  
  313.     pb.pb_alloc_length = sizeof(pc);
  314.     pb.pb_buffer = (caddr_t)&pc;
  315.  
  316.     if (ioctl(d->fd, CDROM_PLAYBACK_CONTROL, &pb))
  317.         return (-1);
  318.  
  319.     return (0);
  320. }
  321.  
  322. /*
  323.  * Pause the CD.
  324.  */
  325. int
  326. gen_pause(d)
  327.     struct wm_drive    *d;
  328. {
  329.     return (ioctl(d->fd, CDROM_PAUSE_PLAY));
  330. }
  331.  
  332. /*
  333.  * Resume playing the CD (assuming it was paused.)
  334.  */
  335. int
  336. gen_resume(d)
  337.     struct wm_drive    *d;
  338. {
  339.     return (ioctl(d->fd, CDROM_RESUME_PLAY));
  340. }
  341.  
  342. /*
  343.  * Stop the CD.
  344.  */
  345. int
  346. gen_stop(d)
  347.     struct wm_drive *d;
  348. {
  349.     return (ioctl(d->fd, SCSI_STOP_UNIT));
  350. }
  351.  
  352. /*
  353.  * Play the CD from one position to another (both in frames.)
  354.  */
  355. int
  356. gen_play(d, start, end)
  357.     struct wm_drive    *d;
  358.     int        start, end;
  359. {
  360.     struct cd_play_audio_msf    msf;
  361.  
  362.     msf.msf_starting_M_unit    = start / (60*75);
  363.     msf.msf_starting_S_unit    = (start % (60*75)) / 75;
  364.     msf.msf_starting_F_unit    = start % 75;
  365.     msf.msf_ending_M_unit    = end / (60*75);
  366.     msf.msf_ending_S_unit    = (end % (60*75)) / 75;
  367.     msf.msf_ending_F_unit    = end % 75;
  368.  
  369.     if (ioctl(d->fd, SCSI_START_UNIT))
  370.         return (-1);
  371.     if (ioctl(d->fd, CDROM_PLAY_MSF, &msf))
  372.         return (-2);
  373.  
  374.     return (0);
  375. }
  376.  
  377. /*
  378.  * Eject the current CD, if there is one.
  379.  */
  380. int
  381. gen_eject(d)
  382.     struct wm_drive    *d;
  383. {
  384.     /* On some systems, we can check to see if the CD is mounted. */
  385.     struct stat    stbuf;
  386.     struct ustat    ust;
  387.  
  388.     if (fstat(d->fd, &stbuf) != 0)
  389.         return (-2);
  390.  
  391.     /* Is this a mounted filesystem? */
  392.     if (ustat(stbuf.st_rdev, &ust) == 0)
  393.         return (-3);
  394.  
  395.     return (ioctl(d->fd, CDROM_EJECT_CADDY));
  396. }
  397.  
  398. /*
  399.  * unscale_volume(cd_vol, max)
  400.  *
  401.  * Given a value between min_volume and max_volume, return the volume slider
  402.  * value needed to achieve that value.
  403.  *
  404.  * Rather than perform floating-point calculations to reverse the above
  405.  * formula, we simply do a binary search of scale_volume()'s return values.
  406.  */
  407. static int
  408. unscale_volume(cd_vol, max)
  409.     int    cd_vol, max;
  410. {
  411.     int    vol = 0, top = max, bot = 0, scaled;
  412.  
  413.     while (bot <= top)
  414.     {
  415.         vol = (top + bot) / 2;
  416.         scaled = scale_volume(vol, max);
  417.         if (cd_vol == scaled)
  418.             break;
  419.         if (cd_vol < scaled)
  420.             top = vol - 1;
  421.         else
  422.             bot = vol + 1;
  423.     }
  424.     
  425.     if (vol < 0)
  426.         vol = 0;
  427.     else if (vol > max)
  428.         vol = max;
  429.  
  430.     return (vol);
  431. }
  432.  
  433. /*
  434.  * Read the initial volume from the drive, if available.  Each channel
  435.  * ranges from 0 to 100, with -1 indicating data not available.
  436.  */
  437. int
  438. gen_get_volume(d, left, right)
  439.     struct wm_drive    *d;
  440.     int        *left, *right;
  441. {
  442.     struct cd_playback        pb;
  443.     struct cd_playback_status    ps;
  444.  
  445.     bzero((char *)&pb, sizeof(pb));
  446.     bzero((char *)&ps, sizeof(ps));
  447.  
  448.     pb.pb_alloc_length = sizeof(ps);
  449.     pb.pb_buffer = (caddr_t)&ps;
  450.  
  451.     if (d->fd >= 0)
  452.     {
  453.         if (ioctl(d->fd, CDROM_PLAYBACK_STATUS, &pb))
  454.             *left = *right = -1;
  455.         else
  456.         {
  457.             *left = unscale_volume(ps.ps_chan0_volume, 100);
  458.             *right = unscale_volume(ps.ps_chan1_volume, 100);
  459.         }
  460.     }
  461.     else
  462.         *left = *right = -1;
  463.  
  464.     return (0);
  465. }
  466.  
  467. /*
  468.  * Send an arbitrary SCSI command to a device.
  469.  */
  470. int
  471. wm_scsi(d, cdb, cdblen, retbuf, retbuflen, getreply)
  472.     struct wm_drive    *d;
  473.     unsigned char    *cdb;
  474.     int        cdblen;
  475.     void        *retbuf;
  476.     int        retbuflen;
  477.     int        getreply;
  478. {
  479.     /* ULTRIX doesn't have a SCSI passthrough interface, does it? */
  480.     return (-1);
  481. }
  482.  
  483. /*
  484.  * fgetline()
  485.  *
  486.  *   Simulate fgets, but joining continued lines in the output of uerf.
  487.  */
  488.  
  489. #define BUF_SIZE        85              /* Max length of a (real) line */
  490.  
  491. char *
  492. fgetline(fp)
  493. FILE    *fp;
  494. {
  495.         static char     *retval = NULL;
  496.         static char     holdbuf[BUF_SIZE + 1];
  497.         char            tmp[BUF_SIZE + 1];
  498.         char            *stmp;
  499.  
  500.         if (!retval) {
  501.                 retval = malloc(BUF_SIZE * 3);  /* 3 lines can be joined */
  502.                 if (!retval)
  503.                         return(NULL);
  504.                 else
  505.                         *retval = '\0';
  506.         }
  507.  
  508.         if (*holdbuf) {
  509.                 strcpy(retval, holdbuf);
  510.                 retval[strlen(retval)-1] = '\0';
  511.                 memset(holdbuf, 0, BUF_SIZE+1);
  512.         }
  513.         while (fgets(tmp, BUF_SIZE, fp)) {
  514.                 stmp = tmp + strspn(tmp, " \t");
  515.                 if (*stmp == '_') {                     /* Continuation line */
  516.             retval[strlen(retval)-1] = '\0';   /* Trim off C/R */
  517.                         strcat(retval, stmp+1);
  518.                 } else {
  519.                         if (*retval) {
  520.                                 strcpy(holdbuf, tmp);
  521.                                 holdbuf[strlen(holdbuf)-1] = -1;
  522.                                 return retval;
  523.                         } else {             /* First line read, keep reading */
  524.                                 strcat(retval, stmp);
  525.                                 retval[strlen(retval)-1] = '\0';
  526.                         }
  527.                 }
  528.         }
  529.         return NULL;
  530. }
  531.  
  532. /*
  533.  * Open the CD device and figure out what kind of drive is attached.
  534.  */
  535. int
  536. wmcd_open(d)
  537.     struct wm_drive    *d;
  538. {
  539.     int        fd;
  540.     static int    warned = 0;
  541.  
  542.     if (d->fd >= 0)        /* Device already open? */
  543.         return (0);
  544.  
  545.     if (cd_device == NULL)
  546.         find_cdrom();
  547.  
  548.     d->fd = open(cd_device, 0);
  549.     if (d->fd < 0)
  550.     {
  551.         if (errno == EACCES)
  552.         {
  553.             if (!warned)
  554.             {
  555.                 fprintf(stderr,
  556.         "As root, please run\n\nchmod 666 %s\n\n%s\n", cd_device,
  557.         "to give yourself permission to access the CD-ROM device.");
  558.                 warned++;
  559.             }
  560.         }
  561.         else if (errno != EINTR)
  562.         {
  563.             perror(cd_device);
  564.             exit(1);
  565.         }
  566.  
  567.         /* No CD in drive. */
  568.         return (1);
  569.     }
  570.  
  571.     if (warned)
  572.     {
  573.         warned = 0;
  574.         fprintf(stderr, "Thank you.\n");
  575.     }
  576.  
  577.     /* Now fill in the relevant parts of the wm_drive structure. */
  578.     fd = d->fd;
  579.     *d = *(find_drive_struct("", "", ""));
  580.     d->fd = fd;
  581.  
  582.     (d->init)(d);
  583.  
  584.     return (0);
  585. }
  586.  
  587. void
  588. keep_cd_open() { }
  589.  
  590. #endif
  591.